package com.jf.identity.task.service;

import com.jf.identity.aop.AtomikosTransaction;
import com.jf.identity.dao.exedc.ExedcStaticDao;
import com.jf.identity.dao.vis.ExamSessionCountDao;
import com.jf.identity.dao.visexamid.ExamineeDao;
import com.jf.identity.entity.*;
import com.jf.identity.holder.ExamBaseParamHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import javax.transaction.UserTransaction;
import java.nio.charset.Charset;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * @author FCG
 */
@Component
public class VerifyInfoTaskServiceImpl implements VerifyInfoTaskService {
    @Resource
    private ExamineeDao examineeDao;
    @Resource
    private ExamSessionCountDao examSessionCountDao;
    @Resource
    private ExamBaseParamHolder examBaseParamHolder;
    @Resource
    private ExedcStaticDao exedcStaticDao;
//    @Resource(name = "userTransactionImp")
//    private UserTransaction userTransaction;

    @AtomikosTransaction
    @Override
    public VerifyInfoTaskCount setVerifyInfo(VerifyInfoFeedBack verifyInfoFeedBack) {
        int info;
        int trace;
        int staticV;
        int enterS;
        try {
            ExamBaseParam examBaseParam = getExamBaseParam(verifyInfoFeedBack);
            examBaseParamHolder.setExamBaseParam(examBaseParam);
            List<VerifyInfo> verifyInfos = verifyInfoFeedBack.getValidateInfo();
            List<VerifyTrace> verifyTraces = new ArrayList<>();
            //更新“入场状态”的 verifyInfo list:
            List<VerifyInfo> enterStatusVerifyInfos = new ArrayList<>(verifyInfos.size());
            for (VerifyInfo verifyInfo : verifyInfos) {
                //TODO 是否对校验字段 "QKBJ"?
                if ("Y".equals(verifyInfo.getQKBJ())) {
                    //insertAbsentInfo();
                    break;
                }
                //验证信息：
                String verifyMd5 = getFinalVerifyInfoUid(examBaseParam, verifyInfo);
                verifyInfo.setUid(verifyMd5);
                verifyInfo.setExamBaseParam(examBaseParam);
                //轨迹list:
                List<VerifyTrace> traceList = verifyInfo.getYZGJ();
                if (traceList.isEmpty()) {
                    throw new IllegalStateException("验证轨迹不能为空");
                }
                for (VerifyTrace verifyTrace : traceList) {
                    verifyTrace.setExamBaseParam(examBaseParam);
                    verifyTrace.setKSH(verifyInfo.getKSH());
                    verifyTrace.setSFZJH(verifyInfo.getSFZJH());
                    verifyTrace.setYZSB(verifyInfo.getYZSB());
                    verifyTrace.setYZSJ(verifyInfo.getYZSJ());
                    String traceMd5 = getVerifyTraceUid(examBaseParam, verifyTrace);
                    verifyTrace.setUid(traceMd5);
                }
                verifyTraces.addAll(traceList);
                //更新入场信息
                VerifyInfo enterVerify = new VerifyInfo();
                String uid = getEnterStatusUid(examBaseParam, verifyInfo);
                enterVerify.setUid(uid);
                enterVerify.setYZJG(verifyInfo.getYZJG());
                enterVerify.setDateTime(verifyInfoFeedBack.getDateTime());
                enterStatusVerifyInfos.add(enterVerify);
            }
            //上传考生入场信息
            enterS = updateEnterStatus(enterStatusVerifyInfos, examBaseParam);
            if (enterS == 0) {
                throw new IllegalStateException("上传考生入场信息至 v_examinee_final_vodinfo_" + examBaseParam.getExamSessionNum() + " 失败;");
            }
            //上传考生验证信息
            info = insertFinalVerifyInfos(verifyInfos);
            //上传考生验证轨迹
            trace = insertVerifyTrace(verifyTraces);
            //上传验证总计信息
            staticV = updateStaticValidation(examBaseParam);

        } catch (Exception e) {
            throw new IllegalStateException(e);
        } finally {
            examBaseParamHolder.remove();
        }
        return new VerifyInfoTaskCount(info, trace, staticV, enterS);
    }

    /**
     * 生成 v_examinee_final_vodinfo_考试场次 uid = {考试计划编号}_{准考证号}_{场次}
     *
     * @param examBaseParam "examId":"考试计划编号",
     *                      "examSessionNum":"考试场次"
     * @param verifyInfo    "KSH":"考生号"
     * @return uid
     */
    private String getEnterStatusUid(ExamBaseParam examBaseParam, VerifyInfo verifyInfo) {
        return examBaseParam.getExamId() + "_" + verifyInfo.getKSH() + "_" + examBaseParam.getExamSessionNum();
    }

    /**
     * 从 jf_vis_db_20181009.i_ksyzgj  jf_vis_db_20181009.i_ksyzxx 取数据，
     * 插入到 jf_exedc_db.i_statistic_validation
     */
    public int updateStaticValidation(ExamBaseParam examBaseParam) {
        StaticValidation staticValidation = new StaticValidation();
//        for (VerifyInfo verifyInfo : verifyInfos) {
        //总人数:从考试计划处获取
        Integer total = examSessionCountDao.getExamineeSum(examBaseParam);
        if (total == null) {
            throw new IllegalStateException("当前场次无考生总人数信息" + examBaseParam.toString());
        }
        int fingureSum = 0;
        int faceSum = 0;
        int manualSum = 0;
        //已验证人数
        int validatedSum = examineeDao.getVerifyInfoCount(examBaseParam);
        //都已验证
        if (validatedSum >= total) {
            validatedSum = total;
        }
        //未验证人数
        int unValidatedSum = total - validatedSum;
        staticValidation.setOrgCode(examBaseParam.getOrgCode());
        staticValidation.setExamId(examBaseParam.getExamId());
        staticValidation.setExamSessionNum(examBaseParam.getExamSessionNum());
        List<VerifyTrace> verifyTraces = examineeDao.getVerifyTraces(examBaseParam);
        for (VerifyTrace verifyTrace : verifyTraces) {
            if ("1".equals(verifyTrace.getYZXJG())) {
                //"YZX": ""验证项,1：刷身份证  2:身份证ID号验证3：人脸 4：指纹5:人工审核"
                switch (verifyTrace.getYZX()) {
                    case "4":
                        fingureSum++;
                        break;
                    case "3":
                        faceSum++;
                        break;
                    case "5":
                        manualSum++;
                        break;
                    default:
                        break;
                }
            }
        }
        DecimalFormat df = new DecimalFormat("0.00%");
        staticValidation.setTotal(total);
        staticValidation.setValidatedSum(validatedSum);
        staticValidation.setAdmissionRate(df.format((double) validatedSum / total));
        staticValidation.setFaceSum(faceSum);
        staticValidation.setFaceRate(df.format((double) faceSum / validatedSum));
        staticValidation.setFingureSum(fingureSum);
        staticValidation.setFingureRate(df.format((double) fingureSum / validatedSum));
        staticValidation.setManualSum(manualSum);
        staticValidation.setManualRate(df.format((double) manualSum / validatedSum));
        staticValidation.setUnValidatedSum(unValidatedSum);
        staticValidation.setFinalPassRate(df.format((double) (faceSum + fingureSum + manualSum) / validatedSum));
        int i = exedcStaticDao.insertValidatation(staticValidation);
        return i != 0 ? 1 : i;
    }


    public int insertFinalVerifyInfos(List<VerifyInfo> verifyInfos) {
        int size = verifyInfos.size();
        //增加考生验证信息
        int i = examineeDao.insertExamineeVerifyInfo(verifyInfos);
        return i >= size ? size : i;
    }

    public int insertVerifyTrace(List<VerifyTrace> verifyTraces) {
        int size = verifyTraces.size();
        int i = examineeDao.insertExamineeVerifyTrace(verifyTraces);
        return i >= size ? size : i;
    }

    public int updateEnterStatus(List<VerifyInfo> verifyInfos, ExamBaseParam examBaseParam) {
        return examineeDao.updateFinalVodInfos(verifyInfos, examBaseParam);
    }

    /**
     * 考生验证信息uid i_ksyzxx MD5(orgCode+examId+examSessionNum+KSH)
     *
     * @param examBaseParam orgCode,examId,examSessionNum
     * @param verifyInfo    KSH
     * @return uid
     */
    private String getFinalVerifyInfoUid(ExamBaseParam examBaseParam, VerifyInfo verifyInfo) {
        String orgCode = examBaseParam.getOrgCode();
        String examId = examBaseParam.getExamId();
        String examSessionNum = examBaseParam.getExamSessionNum();
        String examineeNum = verifyInfo.getKSH();
        String uid = orgCode + examId + examSessionNum + examineeNum;
        return DigestUtils.md5DigestAsHex(uid.getBytes(Charset.forName("UTF-8")));
    }

    private ExamBaseParam getExamBaseParam(VerifyInfoFeedBack verifyInfoFeedBack) {
        String orgCode = verifyInfoFeedBack.getOrgCode();
        String examSessionNum = verifyInfoFeedBack.getExamSessionNum();
        String examId = verifyInfoFeedBack.getExamId();
        ExamBaseParam examBaseParam = new ExamBaseParam();
        examBaseParam.setOrgCode(orgCode);
        examBaseParam.setExamId(examId);
        examBaseParam.setExamSessionNum(examSessionNum);
        return examBaseParam;
    }

    /**
     * 验证轨迹 uid MD5(orgCode+examId+examSessionNum+KSH+verifyTypeId)
     *
     * @param examBaseParam orgCode+examId+examSessionNum
     * @param verifyTrace   KSH+verifyTypeId
     * @return uid
     */
    private String getVerifyTraceUid(ExamBaseParam examBaseParam, VerifyTrace verifyTrace) {
        String orgCode = examBaseParam.getOrgCode();
        String examId = examBaseParam.getExamId();
        String examSessionNum = examBaseParam.getExamSessionNum();
        String examineeNum = verifyTrace.getKSH();
        String verifyTypeId = verifyTrace.getYZX();
        String uid = orgCode + examId + examSessionNum + examineeNum + verifyTypeId;
        return DigestUtils.md5DigestAsHex(uid.getBytes(Charset.forName("UTF-8")));
    }
}
